package icdecs.action;

import icdecs.dao.GetListDAO;
import icdecs.model.DataModel;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.validator.DynaValidatorForm;

/**
 * This is GetList action
 * 
 * 
 */
public class GetListAction extends Action {
	private final static String SUCCESS = "success";
	private final static String FAILURE = "failure";

	private final static String PREFIX = "icdecs";
	private final static String URI_SCHEMA = "http://localhost:8080/icdecs/Schema";

	private final static String ELEMENT_REQUEST = "getListRequest";
	private final static String ELEMENT_AUTH_INFO = "authenticationInfo";
	private final static String ELEMENT_AUTH_ID = "AuthenticationID";
	private final static String ELEMENT_AUTH_KEY = "AuthenticationKey";
	private final static String ELEMENT_ORGA_ID = "OrganizationID";

	private final static String ELEMENT_RESPONSE = "getListResponse";

	// ----------Input--------------
	private String authenticationId;
	private String authenticationKey;
	private String organizationId;

	// ----------Output-------------
	private int statusCode;
	private String statusMessage;
	private String generatedTime;
	private String numberOfCard;

	private List<DataModel> listData;

	private List<String> listCardId;

	@SuppressWarnings("rawtypes")
	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {

		DynaValidatorForm getListForm = (DynaValidatorForm) form;

		authenticationId = (String) getListForm.get("authenticationId");
		authenticationKey = (String) getListForm.get("authenticationKey");
		organizationId = (String) getListForm.get("organizationId");

		String url = "http://localhost:8080/icdecs/services/getList";

		listCardId = new ArrayList<String>();
		SOAPConnection soapConnection = null;
		SOAPMessage soapResponse;

		try {

			soapConnection = SOAPConnectionFactory.newInstance()
					.createConnection();
			// Get list by SOAP
			soapResponse = soapConnection.call(createSOAPRequest(), url);

			// Print SOAP response
			printSOAPResponse(soapResponse);

			SOAPEnvelope envelope = soapResponse.getSOAPPart().getEnvelope();

			SOAPBody soapBody = envelope.getBody();
			Iterator bodyElements = soapBody.getChildElements(envelope
					.createName(ELEMENT_RESPONSE, PREFIX, URI_SCHEMA));

			SOAPElement bodyElement = (SOAPElement) bodyElements.next();
			Iterator elements = bodyElement.getChildElements();

			while (elements.hasNext()) {
				Iterator listChild = ((SOAPElement) elements.next())
						.getChildElements();
				while (listChild.hasNext()) {
					SOAPElement elementChild = (SOAPElement) listChild.next();
					if (elementChild.getLocalName().equals("StatusCode")) {
						setStatusCode(Integer.parseInt(elementChild.getValue()));
						continue;
					}
					if (elementChild.getLocalName().equals("StatusMessage")) {
						setStatusMessage(elementChild.getValue());
						continue;
					}
					if (elementChild.getLocalName().equals("GeneratedTime")) {
						setGeneratedTime(elementChild.getValue());
						continue;
					}
					if (elementChild.getLocalName().equals("Numberofcards")) {
						setNumberOfCard(elementChild.getValue());
						continue;
					}
					if (elementChild.getLocalName().equals("CardID")) {
						listCardId.add(elementChild.getValue());
						continue;
					}
				}
			}

			if (statusCode == 200) {
				listData = new ArrayList<DataModel>();
				DataModel dataModel = null;
				for (int i = 0; i < listCardId.size(); i++) {
					dataModel = new DataModel(authenticationId, organizationId,
							listCardId.get(i), generatedTime);
					listData.add(dataModel);
				}

				if (new GetListDAO().InsertData(listData)) {

					getListForm.set("authenticationId", null);
					getListForm.set("authenticationKey", null);
					getListForm.set("organizationId", null);
					getListForm.set("generatedTime", generatedTime);
					getListForm.set("numberOfCard", numberOfCard);
					getListForm.set("listCardId", listCardId);
					getListForm.set("statusMessage", statusMessage);
					return mapping.findForward(SUCCESS);
				} else {
					getListForm.set("statusMessage",
							"Insert data into database is failed!");
					return mapping.findForward(FAILURE);
				}
			} else {
				getListForm.set("statusMessage", statusMessage);
				return mapping.findForward(FAILURE);
			}

		} catch (UnsupportedOperationException e) {
			e.printStackTrace();
		} catch (SOAPException e) {
			e.printStackTrace();
			getListForm.set("statusMessage", "Service is died!");
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			getListForm.set("statusMessage",
					"Can not connect database on client");
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		} finally {
			try {
				soapConnection.close();
			} catch (SOAPException e) {
				e.printStackTrace();
			}
		}

		return mapping.findForward(FAILURE);
	}

	private SOAPMessage createSOAPRequest() throws SOAPException, IOException {
		MessageFactory messageFactory = MessageFactory.newInstance();
		SOAPMessage soapMessage = messageFactory.createMessage();
		SOAPPart soapPart = soapMessage.getSOAPPart();

		String serverXSD = "http://www.w3.org/2001/XMLSchema";
		String serverXSI = "http://www.w3.org/2001/XMLSchema-instance";

		SOAPEnvelope envelope = soapPart.getEnvelope();
		envelope.addNamespaceDeclaration("xsd", serverXSD);
		envelope.addNamespaceDeclaration("xsi", serverXSI);
		envelope.addNamespaceDeclaration(PREFIX, URI_SCHEMA);

		SOAPBody soapBody = envelope.getBody();
		SOAPElement elementGetListRequest = soapBody.addChildElement(
				ELEMENT_REQUEST, PREFIX);

		SOAPElement elementAuthInfo = elementGetListRequest.addChildElement(
				ELEMENT_AUTH_INFO, PREFIX);

		SOAPElement elementAuthId = elementAuthInfo.addChildElement(
				ELEMENT_AUTH_ID, PREFIX);
		elementAuthId.addTextNode(authenticationId);
		SOAPElement elementAuthKey = elementAuthInfo.addChildElement(
				ELEMENT_AUTH_KEY, PREFIX);
		elementAuthKey.addTextNode(authenticationKey);
		SOAPElement elementOrgaId = elementAuthInfo.addChildElement(
				ELEMENT_ORGA_ID, PREFIX);
		elementOrgaId.addTextNode(organizationId);

		soapMessage.getMimeHeaders().setHeader("SoapAction", "");

		soapMessage.saveChanges();

		/* Print the request message */
		System.out.print("Request SOAP Message = ");
		soapMessage.writeTo(System.out);
		System.out.println();

		return soapMessage;
	}

	public String getStatusMessage() {
		return statusMessage;
	}

	public void setStatusMessage(String statusMessage) {
		this.statusMessage = statusMessage;
	}

	public String getNumberOfCard() {
		return numberOfCard;
	}

	public void setNumberOfCard(String numberOfCard) {
		this.numberOfCard = numberOfCard;
	}

	public String getGeneratedTime() {
		return generatedTime;
	}

	public void setGeneratedTime(String generatedTime) {
		this.generatedTime = generatedTime;
	}

	public int getStatusCode() {
		return statusCode;
	}

	public void setStatusCode(int statusCode) {
		this.statusCode = statusCode;
	}

	/**
	 * Method used to print the SOAP Response
	 * 
	 * @throws SOAPException
	 * @throws TransformerException
	 */
	private static void printSOAPResponse(SOAPMessage soapResponse)
			throws SOAPException, TransformerException {
		TransformerFactory transformerFactory = TransformerFactory
				.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		Source sourceContent = soapResponse.getSOAPPart().getContent();
		System.out.print("\nResponse SOAP Message = ");
		StreamResult result = new StreamResult(System.out);
		transformer.transform(sourceContent, result);
	}

}
